import { ContentEventer } from "./event"

const MAX_TIME_OUT = 65 * 1000

/**
 * 异步跨线程调用
 * @param method 
 * @param arg 
 * @param timeout 
 * @returns 
 */
export function callChromeMethod<T>(method: string, arg?: any, timeout: number = MAX_TIME_OUT): Promise<T> {
    return new Promise((resolve, reject) => {
        let timer: any
        if (typeof chrome.runtime === 'undefined' || typeof chrome.runtime.sendMessage === 'undefined') {
            const msgHandler = (event: MessageEvent) => {
                if (!event.data) {
                    return
                }
                const { type, data, message, state } = event.data

                if (event.source === window) {
                    return
                }

                if (type === method) {
                    window.removeEventListener('message', msgHandler)
                    clearTimeout(timer)
                    if (state) {
                        resolve(data)
                    } else {
                        reject(message)
                    }
                }
            }
            clearTimeout(timer)
            timer = setTimeout(() => {
                window.removeEventListener('message', msgHandler)
                reject('timeout')
            }, timeout)
            const topWin = window.parent.window
            window.addEventListener('message', msgHandler)
            topWin.postMessage({ type: method, data: arg }, '*')
        } else {
            chrome.runtime.sendMessage({ type: method, data: arg }, (result: ChromeResponse) => {
                if (!result) {
                    reject('chrome: unknown error,method:' + method)
                }
                if (result?.state) {
                    resolve(result?.data)
                } else {
                    reject(result?.message)
                }

            })
        }

    })
}

export function initSandBoxEvents() {
    window.addEventListener('message', async (event: MessageEvent) => {
        if (!event.data) {
            return
        }
        const { type, data } = event.data
        if (event.source === window || !event.source) {
            return
        }
        const sandBox = event.source as Window
        callChromeMethod(type, data).then((res: any) => {
            sandBox.postMessage({
                type,
                state: true,
                data: res
            }, '*')
        }).catch((err: any) => {
            sandBox.postMessage({
                type,
                state: false,
                data: undefined,
                message: String(err)
            }, '*')
        })
    })
}

export function getResourceSuffix(res: ResourceInfo) {
    if (res.type === 'canvas') {
        return '.png'
    } else if (res.type === 'image') {
        if (res.name.includes('.jpg') || res.name.includes('.jpeg')) {
            return '.jpg'
        } else if (res.name.includes('svg')) {
            return '.svg'
        } else if (res.name.includes('webp')) {
            return '.webp'
        } else {
            return '.png'
        }
    } else if (res.type === 'media') {
        const matchAudio = res.name.match(/.(mp3|wav|ogg|m4a|aac)/)
        const matchVideo = res.name.match(/.(mp4|webm)/)
        if (matchAudio) {
            return matchAudio[0]
        } else if (matchVideo) {
            return matchVideo[0]
        } else {
            return '.mp4'
        }
    } else if (res.type === 'script') {
        return '.js'
    } else if (res.type === 'stylesheet') {
        return '.css'
    } else if (res.type === 'font') {
        return '.ttf'
    } else if (res.type === '3dmodle') {
        const match = res.name.match(/.(glb|gltf|fbx|obj|stl|ply|dae)/)
        if (match) {
            return match[0]
        } else {
            return '.glb'
        }
    } else {
        return ''
    }
}

export async function awaitTime(time: number) {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve(true)
        }, time)
    })
}

export function callContentMethod<T>(method: string, arg?: any) {
    return ContentEventer.sendMessage<T>({
        type: method,
        data: arg
    })
}

export function callContentMethodSync<T>(method: string, arg?: any) {
    return ContentEventer.sendMessageSync<T>({
        type: method,
        data: arg
    })
}

export function getObjectPropty(){
    
}